#pragma once

#include<iostream>
#include<unistd.h>
#include<cstdlib>
#include<strings.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<pthread.h>

#include"Log.hpp"


const int BACKLOG=5;

class TcpServer
{
private:
    uint16_t port;
    int listen_sock;
    static TcpServer* svr;
    

    TcpServer(uint16_t _port):port(_port),listen_sock(-1)
    {}
    TcpServer(const TcpServer&s)=delete;
    TcpServer& operator=(const TcpServer&)=delete;

public:
    static TcpServer* GetInstance(uint16_t _port)
    {
        pthread_mutex_t mtx=PTHREAD_MUTEX_INITIALIZER;
        if(svr==nullptr)
        {
            pthread_mutex_lock(&mtx);
            if(svr==nullptr)
            {
                svr=new TcpServer(_port);
                svr->InitServer();
            }
            pthread_mutex_unlock(&mtx);
        }
        return svr;
    }


    void InitServer()
    {
        Socket();
        Bind();
        Listen();   
    }

    void Socket()
    {
        listen_sock=socket(AF_INET,SOCK_STREAM,0);
        if(listen_sock<0)
        {
            LOG(FATAL,"socket error");
            exit(1);
        }
        int opt=1;
        setsockopt(listen_sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
        LOG(INFO,"socket success");
    }

    void Bind()
    {
        struct sockaddr_in local;
        bzero(&local,sizeof(local));
        local.sin_family=AF_INET;
        local.sin_port=htons(port);
        local.sin_addr.s_addr=INADDR_ANY;//云服务器不能直接绑定公网IP
        
        if(bind(listen_sock,(struct sockaddr*)&local,sizeof(local))<0)
        {
            LOG(FATAL,"Bind error");
            exit(2);
        }
        LOG(INFO,"Bind socket success");
    }

    void Listen()
    {
        if(listen(listen_sock,BACKLOG)<0)
        {
            LOG(FATAL,"Listen error");
            exit(3);
        }
        LOG(INFO,"listen start....");
    }

    int Sock()
    {
        return listen_sock;
    }

    ~TcpServer()
    {
        if(listen_sock>=0)
        {
            close(listen_sock);
        }
    }
};
TcpServer* TcpServer::svr=nullptr;